Passed
Push — master ( 84becd...1ef449 )
by Andrew
06:10 queued 03:17
created

index.ts ➔ PluginCritical   B

Complexity

Conditions 8

Size

Total Lines 49
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 8.0747

Importance

Changes 0
Metric Value
eloc 35
dl 0
loc 49
ccs 17
cts 19
cp 0.8947
rs 7.1733
c 0
b 0
f 0
cc 8
crap 8.0747
1
import {Plugin} from 'rollup';
2 1
import path from 'path';
3 1
const critical = require('critical');
4
5 1
const criticalSuffix = '_critical.min.css';
6
7
/**
8
 * Default `criticalConfig` passed in to `critical`
9
 */
10 1
const defaultCriticalConfig: Partial<CriticalConfig> = {
11
  inline: false,
12
  minify: true,
13
  extract: false,
14
  width: 1200,
15
  height: 1200,
16
  penthouse: {
17
    blockJSRequests: false
18
  }
19
};
20
21
interface CriticalPages {
22
  /** Combined with `criticalUrl` to determine the URLs to scrape for Critical CSS */
23
  uri: string;
24
  /** Critical CSS files are named with the `template` path, and saved to the `criticalBase` directory */
25
  template: string;
26
}
27
28
interface CriticalPluginConfig {
29
  /**
30
   * The base URL to use in combination with the `criticalPages` `uri`s to determine the URLs to scrape for Critical CSS.
31
   * This can also be a file system path. This is combined with `criticalPages.uri`
32
   * to determine pages to scrap for critical CSS.
33
   * Determines the `criticalConfig.src` property
34
   */
35
  criticalUrl: string;
36
  /**
37
   * The base file system path to where the generated Critical CSS file should be saved.
38
   * This is combined with `criticalPages.template` with `_critical.min.css` appended
39
   * to it to determine the saved critical CSS file name.
40
   * Determines the `criticalConfig.target` property
41
   */
42
  criticalBase?: string;
43
  /**
44
   * An array objects that contain the page `uri`s that are combined with the `criticalUrl` to
45
   * determine the URLs to scrape for Critical CSS. The resulting files are named with the
46
   * `template` path, and saved to the `criticalBase` directory
47
   */
48
  criticalPages: Partial<CriticalPages>[];
49
  /**
50
   * This is the full [config for critical](https://github.com/addyosmani/critical#options) that is passed
51
   * through to the `critical` package.
52
   * You may optionally override any properties you like here
53
   */
54
  criticalConfig?: Partial<CriticalConfig>;
55
}
56
57
/**
58
 * [Vite.js](https://vitejs.dev/) & [Rollup](https://rollupjs.org/) plugin for generating critical CSS
59
 * that uses the [critical](https://github.com/addyosmani/critical) generator under the hood.
60
 *
61
 * @param {CriticalPluginConfig} pluginConfig - the plugin configuration object
62
 * @param {Function} callback - callback upon completion of the critical CSS generation
63
 * @constructor
64
 */
65
function PluginCritical(pluginConfig: CriticalPluginConfig, callback?: Function): Plugin {
66 1
  return {
67
    name: 'critical',
68
    async writeBundle(outputOptions, bundle) {
69 1
      const css: Array<string> = [];
70
      // Find all of the generated CSS assets
71 1
      for (const chunk of Object.values(bundle)) {
72 4
        if (chunk.type === 'asset' && chunk.fileName.endsWith('.css')) {
73 2
          const cssFile = path.join(outputOptions.dir || '', chunk.fileName);
74 1
          css.push(cssFile);
75
        }
76
      }
77
      // If we have no CSS, skip bundle
78 2
      if (!css.length) {
79
        return;
80
      }
81
      // Iterate through the pages
82 1
      for (const page of pluginConfig.criticalPages) {
83 1
        const criticalBase = pluginConfig.criticalBase;
84 1
        const criticalSrc = pluginConfig.criticalUrl + page.uri;
85 1
        const criticalDest = page.template + criticalSuffix;
86
        // Merge in our options
87 1
        const options = Object.assign(
88
            { css },
89
            defaultCriticalConfig,
90
            {
91
              base: criticalBase,
92
              src: criticalSrc,
93
              target: criticalDest,
94
            },
95
            pluginConfig.criticalConfig
96
        );
97
        // Generate the Critical CSS
98 1
        console.log(`Generating critical CSS from ${criticalSrc} to ${criticalDest}`);
99 1
        await critical.generate(options, (err: string) => {
100 2
          if (err) {
101
            console.error(err);
102
          }
103 2
          if (callback) {
104 1
            callback(err);
105
          }
106
        });
107
      }
108
    }
109
  }
110
}
111
112
export default PluginCritical
113